package cn.lg.soar.general.s3;

import cn.lg.soar.common.exceptions.BaseException;
import cn.lg.soar.common.util.AssertUtil;
import cn.lg.soar.common.util.FileTypeUtils;
import cn.lg.soar.common.util.data.DataUtil;
import cn.lg.soar.common.util.listener.SpringUtils;
import cn.lg.soar.general.entity.FileStorage;
import cn.lg.soar.general.service.FileAccessService;
import com.amazonaws.services.s3.model.*;
import lombok.SneakyThrows;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;

/**
 * @author luguoxiang 469599794@qq.com
 * @Date: 2024/3/1 17:25
 * 开源项目：https://gitee.com/lgx1992/lg-soar 求star！请给我star！请帮我点个star！
 */
public class LocalFileTemplateImpl implements FileTemplate {

    private final String rootPath;
    private final int configVersion;

    public LocalFileTemplateImpl(FileStorage storage) {
        this.rootPath = storage.getEndpoint();
        this.configVersion = storage.getVersion();
        File file = new File(this.rootPath);
        if (!file.exists()) {
            AssertUtil.isTrue(file.mkdirs(), "创建目录失败");
        }
    }

    @Override
    @SneakyThrows
    public void createBucket(String bucketName) {
        File file = new File(getBucketPath(bucketName));
        if (!file.exists()) {
            AssertUtil.isTrue(file.mkdirs(), "创建桶失败");
        }
    }

    @Override
    @SneakyThrows
    public List<Bucket> listBuckets() {
        File[] files = new File(this.rootPath).listFiles();
        if (DataUtil.isEmpty(files)) {
            return Collections.emptyList();
        }
        List<Bucket> list = new ArrayList<>(files.length);
        for (File file : files) {
            if (file.isDirectory()) {
                Bucket bucket = new Bucket();
                bucket.setName(file.getName());
                bucket.setCreationDate(new Date(file.lastModified()));
                list.add(bucket);
            }
        }
        return list;
    }

    @Override
    @SneakyThrows
    public void removeBucket(String bucketName) {
        File file = new File(getBucketPath(bucketName));
        Files.deleteIfExists(file.toPath());
    }

    @Override
    public void upload(String bucketName, String filename, InputStream stream) {
        // 指定目标文件的路径
        Path filePath = Paths.get(getFilePath(bucketName, filename));
        try {
            Files.copy(stream, filePath, StandardCopyOption.REPLACE_EXISTING);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    @SneakyThrows
    public String getUrl(String bucketName, String filename, Integer expires) {
        FileAccessService fileAccessService = SpringUtils.getBean(FileAccessService.class);
        return fileAccessService.createTemporaryUrl(true, Long.parseLong(filename.split("\\.")[0]), expires);
    }

    @Override
    public String getUrl(String bucketName, String filename) {
        FileAccessService fileAccessService = SpringUtils.getBean(FileAccessService.class);
        return fileAccessService.createFixedSecretUrl(Long.parseLong(filename.split("\\.")[0]));
    }

    @Override
    @SneakyThrows
    public void removeFile(String bucketName, String filename) {
        String filePath = getFilePath(bucketName, filename);
        Files.deleteIfExists(Paths.get(filePath));
    }

    @Override
    @SneakyThrows
    public InputStream getInputStream(String bucketName, String filename) {
        String filePath = getFilePath(bucketName, filename);
        File file = new File(filePath);
        if (!file.exists()) {
            throw new AmazonS3Exception("The specified key does not exist.");
        }
        return Files.newInputStream(file.toPath());
    }

    @Override
    @SneakyThrows
    public S3Object getObject(String bucketName, String filename) {
        String filePath = getFilePath(bucketName, filename);
        File file = new File(filePath);
        if (!file.exists()) {
            throw new AmazonS3Exception("The specified key does not exist.");
        }
        S3Object object = new S3Object();
        object.setBucketName(bucketName);
        object.setObjectContent(Files.newInputStream(file.toPath()));
        ObjectMetadata metadata = new ObjectMetadata();
        metadata.setContentType(FileTypeUtils.getContentType(file));
        metadata.setContentLength(file.length());
        object.setObjectMetadata(metadata);
        return object;
    }

    @Override
    @SneakyThrows
    public List<S3ObjectSummary> listObjects(String bucketName, String prefix, boolean recursive) {
        String bucketPath = getBucketPath(bucketName);
        File[] files = new File(bucketPath).listFiles();
        if (DataUtil.isEmpty(files)) {
            return Collections.emptyList();
        }
        List<S3ObjectSummary> list = new ArrayList<>(files.length);
        for (File file : files) {
            if (file.isFile() && file.getName().startsWith(prefix)) {
                S3ObjectSummary object = new S3ObjectSummary();
                object.setBucketName(bucketName);
                object.setSize(file.length());
                object.setLastModified(new Date(file.lastModified()));
                list.add(object);
            }
        }
        return list;
    }

    @Override
    public boolean isExist(String bucketName, String filename) {
        String filePath = getFilePath(bucketName, filename);
        return Files.exists(Paths.get(filePath));
    }

    @Override
    public int getConfigVersion() {
        return configVersion;
    }

    @Override
    public void test() {
        File file = new File(rootPath);
        if (file.exists() || file.mkdirs()) {
            return;
        }
        throw new BaseException("A0404", "目录不可用");
    }

    @Override
    public void disconnect() { }

    private String getBucketPath(String bucketName) {
        return rootPath + File.separator + bucketName;
    }

    private String getFilePath(String bucketName, String filename) {
        return getBucketPath(bucketName) + File.separator + filename;
    }

}